/*
	File: data/scripts/tank.nut
	Author: Emmanuel Julien
*/

		Include("data/scripts/soapbox.nut")
		Include("data/scripts/cannon.nut")

/*!
	@short	SteamTank
	@author	Emmanuel Julien
*/

class	SteamTank extends ItemSoapbox 
{
	steam_engine_emitter	=	0

	emitter_speed_scale		=	0.0
	emitter_opacity_scale	=	0.0
	emitter_size_scale		=	0.0

	mesh					=	0

	project_script			=	0

	cannon 					=	0
	fire_timeout			=	0.0

	audio					=	0
	hud_ui					=	0

	//	Game members
	energy					=	100
	shield					=	100
	lives					=	3

	prev_up					=	0
	prev_long_vel			=	0

	device_keyboard			=	0

	function	OnUpdate(item)
	{

/*
		emitter_speed_scale += ((IsAccelerating() ? 2.5 : 1.0) - emitter_speed_scale) * 0.2
		EmitterSetBirthSpeedScale(steam_engine_emitter, emitter_speed_scale)
		emitter_opacity_scale += ((IsAccelerating() ? 1.0 : 0.1) - emitter_opacity_scale) * 0.2
		EmitterSetBirthOpacityScale(steam_engine_emitter, emitter_opacity_scale)
		emitter_size_scale += ((IsAccelerating() ? 1.0 : 0.4) - emitter_size_scale) * 0.2
		EmitterSetBirthSizeScale(steam_engine_emitter, emitter_size_scale)
*/

		if (DeviceKeyPressed(device_keyboard, KeySpace))
		{
			//print("SteamTank::KeyboardSeekFunction(DeviceKeyPress, KeySpace)")
			if ((g_clock - fire_timeout) > SecToTick(Sec(0.25)))
			{
				fire_timeout = g_clock
				cannon.Fire()
				audio.PlaySfxShoot()
			}
		}

		UpdateMeshOrientation(item)
	}

	function	UpdateMeshOrientation(item)
	{
		local	_mat = ItemGetRotationMatrix(item),
				_pos = ItemGetWorldPosition(item),
				_front, _up, _side, ray_d, _up_offset,
				hit, hit_count, ray_spread,
				long_acc, long_vel

		ray_spread = 1.0

		_up_offset = _mat.GetRow(1).Normalize().Scale(0.5)
		
		ray_d = Vector(0,-1,0)

		_up = Vector(0,0,0)
		hit_count = 0

		hit = SceneCollisionRaytrace(g_scene, _pos + _mat.GetRow(2).Scale(ray_spread) + _up_offset, ray_d, self_mask.ground, CollisionTraceAll, Mtr(5.0))
		if (hit.hit)
		{
			_up += ((hit.n * Vector(2.0,1.0,2.0)).Normalize())
			hit_count++
		}


		hit = SceneCollisionRaytrace(g_scene, _pos + _mat.GetRow(0).Scale(ray_spread) + _up_offset, ray_d, -1, 1, Mtr(5.0))
		if (hit.hit)
		{
			_up += ((hit.n * Vector(2.0,1.0,2.0)).Normalize()) 
			hit_count++
		}


		hit = SceneCollisionRaytrace(g_scene, _pos - _mat.GetRow(2).Scale(ray_spread) + _up_offset, ray_d, -1, 1, Mtr(5.0))
		if (hit.hit)
		{
			_up += ((hit.n * Vector(2.0,1.0,2.0)).Normalize())
			hit_count++
		}


		hit = SceneCollisionRaytrace(g_scene, _pos - _mat.GetRow(0).Scale(ray_spread) + _up_offset, ray_d, -1, 1, Mtr(5.0))
		if (hit.hit)
		{
			_up += ((hit.n * Vector(2.0,1.0,2.0)).Normalize())
			hit_count++
		}

		//RendererDrawLine(EngineGetRenderer(g_engine), _pos, _pos + _up)

		if (hit_count == 0)
			_up = Vector(0,1,0)
		else
			_up = _up.Scale(1.0 / (hit_count.tofloat()))

		_front = _mat.GetRow(2)					//	Fetch the front vector from the physic rotation matrix

		//	Evaluate the front vector acceleration
		//	to add it later on to the UP vector.
		long_vel =  ItemGetLinearVelocity(item)
		long_acc =	prev_long_vel - long_vel
		long_acc = Clamp(long_acc.Dot(_front), -0.5, 0.5)
		long_acc = _front.Scale(long_acc)
		prev_long_vel = Lerp(0.5, prev_long_vel, long_vel)

		//RendererDrawLine(EngineGetRenderer(g_engine), _pos, _pos + long_acc)

		_up = _up.Lerp(0.25, prev_up) + long_acc.Scale(0.1)	//	Evaluate a smoothed UP vector
		_side = _up.Cross(_front).Normalize()	//	Compute the side vector
		_front = _side.Cross(_up).Normalize()	//	Re-Compute the new front vector

		/*
			RendererDrawLineColored(EngineGetRenderer(g_engine), _pos, _pos + _up, Vector(1,0,0))		// UP
			RendererDrawLineColored(EngineGetRenderer(g_engine), _pos, _pos + _side, Vector(0,1,0))		// SIDE
			RendererDrawLineColored(EngineGetRenderer(g_engine), _pos, _pos + _front, Vector(0,0,1))	//	FRONT
		*/

		_mat.SetRow(0, _side)
		_mat.SetRow(1, _up)
		_mat.SetRow(2, _front)

//		ItemSetOrientationMethod(mesh, OrientationMatrix)
		ItemSetRotationMatrix(mesh, _mat)	

		prev_up = _up
	}

	function	EnergyUp(increase = 10)
	{
		energy += increase
		if (energy > 100)
			energy = 100
		hud_ui.UpdatePowerGauge(energy)
		audio.PlaySfxPowerUp()
		print("SteamTank::EnergyUp() : energy = " + energy.tostring()) 
	}

	function	EnergyDown(decrease = 10)
	{
		energy -= decrease
		if (energy < 0)
			energy = 0
		hud_ui.UpdatePowerGauge(energy)
		print("SteamTank::EnergyDown() : energy = " + energy.tostring()) 
	}

	function	ShieldUp(increase = 10)
	{
		shield += increase
		if (shield > 100)
			shield = 100
		hud_ui.UpdateShieldGauge(shield)
		audio.PlaySfxPowerUp()
		print("SteamTank::ShieldUp() : shield = " + shield.tostring()) 
	}

	function	TakeDamage(decrease = 10)
	{
		if (shield <= 0)
			EnergyDown()
		else
		{
			shield -= decrease
			shield = Max(0, shield)
			hud_ui.UpdateShieldGauge(shield)
		}

		print("SteamTank::TakeDamage() : shield = " + shield.tostring()) 
	}

	function	OnCollision(item, with_item)
	{
		if (ItemGetName(with_item) == "bullet")
		{
			audio.PlaySfxHit()
			TakeDamage()
		}
	}

	function	OnSetup(item)
	{
		print("SteamTank::OnSetup()")
		base.OnSetup(item)

		project_script = ProjectGetScriptInstance(g_project)
		audio = project_script.audio.player
		hud_ui = project_script.hud_ui

		steam_engine_emitter = /*ItemCastToEmitter*/(SceneFindItemChild(ItemGetScene(item), item, "Steam Emitter"))

		fire_timeout = g_clock
		cannon = PlayerCannon(SceneFindItemChild(ItemGetScene(item), item, "bullet_out"))

		ItemSetCollisionMask(item, with_mask.player)
		ItemSetSelfMask(item, self_mask.player)

		ItemPhysicSetAngularFactor(item, Vector(0,1.0,0))

		mesh = ItemGetChild(item, "tank_mesh")
		prev_up	= Vector(0,1,0)
		prev_long_vel = Vector(0,0,0)

		//	Keyboard
		device_keyboard = GetKeyboardDevice()
	}

	function	OnSetupDone(item)
	{
		if (project_script.tank.current_velocity != 0)
		{
			ItemSetLinearVelocity(item, project_script.tank.current_velocity.Scale(0.8))
			ItemSetPhysicRotation(item, project_script.tank.current_rotation)
		}

		if (project_script.tank.energy != -1)
			energy = project_script.tank.energy

		if (project_script.tank.shield != -1)
			shield = project_script.tank.shield
	}

	function	OnDelete(item)
	{
		print("SteamTank::OnDelete()")
		project_script.tank.current_velocity = ItemGetPreviousLinearVelocity(item)
		project_script.tank.current_rotation = ItemGetPhysicRotation(item)
		project_script.tank.energy = energy
		project_script.tank.shield = shield
	}
}